# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     models.py
    Description:   公共基础model类
 -------------------------------------------------
 """
from datetime import datetime

from django.db import models
from rest_framework.request import Request

from application import settings

table_prefix = settings.TABLE_PREFIX  # 数据库表名前缀


# class SoftDeleteQuerySet(models.QuerySet):
#     """软删除查询集"""
#     pass
#
#
# class SoftDeleteManager(models.Manager):
#     """软删除管理"""
#     pass
#
#
# class SoftDeleteModel(models.Model):
#     """
#     软删除模型
#     一旦继承,就将开启软删除
#     """
#     pass


class CoreModel(models.Model):
    """
    核心标准抽象模型模型,可直接继承使用
    增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称
    """
    id = models.BigAutoField(
        primary_key=True,
        help_text="Id", verbose_name="Id", db_comment="Id"
    )
    description = models.CharField(
        max_length=255,
        null=True, blank=True,
        verbose_name="描述", help_text="描述", db_comment="描述"
    )
    creator = models.ForeignKey(
        to=settings.AUTH_USER_MODEL,
        related_query_name='creator_query', null=True,
        verbose_name='创建人', help_text="创建人", db_comment="创建人",
        on_delete=models.SET_NULL,
        db_constraint=False
    )
    modifier = models.CharField(
        max_length=255,
        null=True, blank=True,
        help_text="修改人", verbose_name="修改人", db_comment="修改人"
    )
    update_datetime = models.DateTimeField(
        auto_now=True, null=True, blank=True,
        help_text="修改时间", verbose_name="修改时间", db_comment="修改时间"
    )
    create_datetime = models.DateTimeField(
        auto_now_add=True, null=True, blank=True,
        help_text="创建时间", verbose_name="创建时间", db_comment="创建时间"
    )

    class Meta:
        # 抽象模型不会创建表
        abstract = True

        verbose_name = '核心模型'
        verbose_name_plural = verbose_name

    @staticmethod
    def get_request_user(request: Request):
        """获取请求中的用户对象"""
        if getattr(request, "user", None):
            return request.user
        return None

    @staticmethod
    def get_request_user_id(request: Request):
        """获取请求中用户的 ID"""
        if getattr(request, "user", None):
            return getattr(request.user, "id", None)
        return None

    @staticmethod
    def get_request_user_name(request: Request):
        """获取请求中用户的名称"""
        if getattr(request, "user", None):
            return getattr(request.user, "name", None)
        return None

    @staticmethod
    def get_request_user_username(request: Request):
        """获取请求中用户的用户名"""
        if getattr(request, "user", None):
            return getattr(request.user, "username", None)
        return None

    def common_insert_data(self, request: Request):
        """
        公用插入数据

        生成一组字典数据，用于插入时填充创建时间 (create_datetime) 和创建人 (creator) 字段。
        它还调用 common_update_data 来获取更新时间和修改人。
        """
        data = {
            'create_datetime': datetime.now(),
            'creator': self.get_request_user(request)
        }
        return {**data, **self.common_update_data(request)}

    def common_update_data(self, request: Request):
        """
        公用更新数据

        生成一组字典数据，用于更新时填充更新时间 (update_datetime) 和修改人 (modifier) 字段。
        """
        return {
            'update_datetime': datetime.now(),
            'modifier': self.get_request_user_username(request)
        }

    # 排除字段
    exclude_fields = [
        '_state',
        'pk',
        'id',
        'create_datetime',
        'update_datetime',
        'creator',
        'creator_id',
        'creator_pk',
        'creator_name',
        'modifier',
        'modifier_id',
        'modifier_pk',
        'modifier_name',
        'dept_belong_id',
    ]

    def get_exclude_fields(self):
        """获取需要排除的字段"""
        return self.exclude_fields

    def get_all_fields(self):
        """获取当前模型的所有字段"""
        return self._meta.fields

    def get_all_fields_names(self):
        """获取当前模型的所有字段名"""
        return [field.name for field in self.get_all_fields()]

    def get_need_fields_names(self):
        """
        获取当前模型需要的字段名

        返回不包含在 exclude_fields 中的字段名称列表。
        这个方法通常用于筛选出需要的字段。
        """
        return [field.name for field in self.get_all_fields() if field.name not in self.exclude_fields]

    def to_data(self):
        """
        将模型转化为字典（去除不包含字段）(注意与to_dict_data区分)。

        去除了 exclude_fields 中的字段。对于关联模型（即外键字段），它会返回关联对象的 id，否则返回字段的值。
        """
        res = {}
        for field in self.get_need_fields_names():
            field_value = getattr(self, field)
            res[field] = field_value.id if (issubclass(field_value.__class__, CoreModel)) else field_value
        return res

    @property
    def DATA(self):
        return self.to_data()

    def to_dict_data(self):
        """
        需要导出的字段（去除不包含字段）（注意与to_data区分）

        返回模型的字典数据，包含所有需要的字段，去除 exclude_fields 中的字段。和 to_data 类似，只不过不对外键字段做特殊处理。
        """
        return {field: getattr(self, field) for field in self.get_need_fields_names()}

    def insert(self, request):
        """
        插入模型

        这个方法用于插入模型数据。它首先确保当前模型实例没有 pk（即未保存），
        然后通过 common_insert_data 获取插入所需的字段（如创建者和创建时间），
        并使用 DICT_DATA 获取其他字段，最终将数据保存到数据库。
        """
        assert self.pk is None, f'模型{self.__class__.__name__}还没有保存到数据中，不能手动指定ID'
        validated_data = {**self.common_insert_data(request), **self.DICT_DATA}
        return self.__class__._default_manager.create(**validated_data)

    def update(self, request, update_data: dict[str, any] = None):
        """
        更新模型
        """
        assert isinstance(update_data, dict), 'update_data必须为字典'
        validated_data = {**self.common_insert_data(request), **update_data}
        for key, value in validated_data.items():
            # 不允许修改id,pk,uuid字段
            if key in ['id', 'pk', 'uuid']:
                continue
            if hasattr(self, key):
                setattr(self, key, value)
        self.save()
        return self


class BaseModel(models.Model):
    """
    基础模型
    可直接继承，一般不需要使用审计字段的模型可以使用
    覆盖字段时，字段名称请勿修改
    """
    update_datetime = models.DateTimeField(
        auto_now=True, null=True, blank=True,
        help_text="修改时间", verbose_name="修改时间", db_comment="修改时间"
    )
    create_datetime = models.DateTimeField(
        auto_now_add=True, null=True, blank=True,
        help_text="创建时间", verbose_name="创建时间", db_comment="创建时间"
    )

    class Meta:
        abstract = True

        verbose_name = "基础模型"
        verbose_name_plural = verbose_name
